# Mybatis 动态SQL

关键字:if where set trim choose when otherwise foreach

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

# 1.if

**if**标签:查询条件是可选项(ps:博客文章搜索)

MyBatis动态SQL场景博客搜索

<select>
       select * from blog where 1=1
        <if test="title != null">
            and title LIKE #{title}
        </if>
        <if test="author != null">
            and type = #{type}
        </if>
        <if test="recommend != null">
            and recommend=#{recommend};
        </if>
    </select>
1
2
3
4
5
6
7
8
9
10
11
12

test为条件,多个条件为and连接,并非&&

where 1=1 if里面加入and

# 2.where

<select>
select * from blog
        <where>
            <if test="title != null">
                and title LIKE #{title}
            </if>
            <if test="author != null">
                and type = #{type}
            </if>
            <if test="recommend != null">
                and recommend=#{recommend};
            </if>
        </where>
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

SQL语句的where关键字变成where标签,包裹住后面的if标签而已。

作用:如果标签中有返回值的话,就插入一个where。

如果标签返回值是以and或者or开头的,这回剔除掉。

​ 例如:如果只有author不为null,则前面的and会自动剔除掉

select * from blog where type=#{type}

# 3.set

类似与where,用于更新语句中。

set用逗号隔开,where用and/or隔开

<update>
update blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="type != null">
                type = #{type},
            </if>
            <if test="recommend != null">
                recommend = #{recommend}
            </if>
        </set>
        where id = #{id};
    </update>  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 4.trim

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>
1
2
3

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

3.3.2 与 set 元素等价的自定义 trim 元素

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>
1
2
3

注意,我们覆盖了后缀值设置,并且自定义了前缀值。

# 5.choose

MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

<select>
        select * from blog where
  <choose>
    <when test="title != null">
       title like #{title}
    </when>
        <when test="type != null">
       type = #{type}
    </when>
    <otherwise>
       recommend = 1;
    </otherwise>
  </choose>
</select>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 6.foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
动态 `SQL` 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
1
2

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

解决SQL 中 in 中遍历的问题,因为通常会传递一个集合,以往要使用Java来遍历改集合中的元素,然后拼接SQL语句。例如下面的SQL语句:传递一个集合{3,5,9}

-- 查询学号为3,5,9的博客的标题,分类,是否推荐 SELECT title,type,recommend FROM blog where id IN(3,5,9); -- 等价于 SELECT title,type,recommend FROM blog where id =3 OR id =5 OR id =9; -- 也等价于:SELECT id,name,major FROM blog where 1=1 and (id=3 or id=5 or id=9);

List<Blog> queryBlogForeach(Map map); 1 SELECT title,type,recommend FROM blog where id IN(3,5,9);

或者其等价SQL:SELECT title,type,recommend FROM blog where id =3 OR id =5 OR id =9;

`(3,5,9)以集合形式保存在map中key为idListforeach要做的就是 遍历idList对应的value获取值

foreah使用:

collection:指定输入对象中的集合属性 上述例子为 idList item:每次遍历生成的对象取的名称 上述例子中可取名id(自定义取名,后面用#{}获取) open:开始遍历时的拼接字符串 上述例子为 左括号 ( close:结束时拼接的字符串 上述例子为 右括号 ) separator:遍历对象之间需要拼接的字符串 上述例子为 逗号 ,

  <!--SELECT title,type,recommend FROM blog where id IN(3,5,9);-->
    <select id="selectBlogForeach" parameterType="map" resultType="com.piao.pojo.Blog">
        SELECT title,type,recommend FROM blog
        <where>
            id in
            <foreach collection="idList" item="id" open="(" close=");" separator=",">
                    #{id}
            </foreach>
        </where>
    </select>

<!-- 若采取它的的等价sql:
SELECT title,type,recommend FROM blog where id =3 OR id =5 OR id =9;
那么foreach写法略有不同
-->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    <select id="selectBlogForeach" parameterType="map" resultType="com.piao.pojo.Blog">
        SELECT title,type,recommend FROM blog
        <where>
            <foreach collection="idList" item="id" open="(" close=");" separator="OR">
                id = #{id}
            </foreach>
        </where>
    </select>
1
2
3
4
5
6
7
8

# 拓展 1 trim元素常用场景 insert语句

一般插入多个数据,但都是可选项,使用自定义trim元素包裹最合适,就是

majorid和majorname都是可选项`

INSERT INTO `major`(`majorid`,`majorname`) values(9,'大数据科学');
INSERT INTO `major`(`majorid`,) values(9);
INSERT INTO `major`(`majorname`) values('大数据科学');

1
2
3
4

可用以下insert元素和trim元素实现:

<insert id="insertBlogByTrim" parameterType="">
       <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="majorid != null">
                majorid,
            </if>
            <if test="majorname != null">
                majorname,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="majorid != null">
                #{adminUserId},
            </if>
            <if test="majorname != null">
                #{loginUserName},
            </if>
        </trim>
</insert>  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 拓展2 SQL片段

在Mapper.xml中可用sql元素提取重复使用的sql片段,在需要复用的地方使用include元素引用即可,类似于c/c++头文件的意思。

sql元素使用 id 来唯一标识该sql片段 include元素中使用 refid 来指定引用的sql片段 例如以下代码:

  <sql id="Base_Column_List">
    category_id, category_name, category_icon, category_rank, is_deleted, create_time
  </sql>

  <select id="findCategoryList" parameterType="Map" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from tb_blog_category
        where is_deleted=0
        order by category_rank desc,create_time desc
        <if test="start!=null and limit!=null">
            limit #{start},#{limit}
        </if>
 </select>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 拓展3 mybatis+多数据库支持

数据库之间实现某个功能的函数可能方法不一样

同时为了方便数据迁移,mybatis提供了多数据库支持,在jdbc中会返回数据库驱动name

需要在配置文件中environment标签里加入 databaseIdProvider标签来启用这个功能。

<environment>
<databaseIdProvider type="DB_VENDOR" />
</environment>
1
2
3

配置数据库Id

<databaseIdProvider type="DB_VENDOR">
  <property name="MySQL" value="mysql"/>       
  <property name="Oracle" value="oracle" />
</databaseIdProvider>
1
2
3
4

利用databaseId属性来指定数据库类型,以使用方言。

<select datebaseId="数据库别名(配置文件中的value)">
    .....
</select>
1
2
3